package dibujar;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JSlider;
import javax.swing.JTextField;

import com.ia.faceDetectetion.downloadMosaicImage;
import com.ia.neuralNetwork.neuralNetwork;

import dibujar.BlobDemo;
import dibujar.BlobFinder.Blob;
import ejemplo.utilidades;

public class reconoceObjetos extends JFrame {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public static downloadMosaicImage dmi = null;
	
	public static int ant = -1;
	public static int contador = 0;
	public static Vector<String> listaLetras;
	protected static Image entryImage;
	public static String sReconocido = "";

	protected static Graphics entryGraphics;
	protected int lastX = -1;
	protected int lastY = -1;
	protected static int downSampleLeft = 0;
	protected static int downSampleRight = 0;
	protected static int downSampleTop = 0;
	protected static int downSampleBottom = 0;
	public static double ratioX;
	public static double ratioY;
	private static int[] pixelMap;
	private static String[] patronesLetras;

	private static BufferedImage imageBuffer;
	private int uX = -1;
	private int uY = -1;
	private static JButton b;
	private JTextField caja;
	private Label labelLetra;
	private Label labelError;
	private static Label labelPrintError;
	private static Label labelOK;
	private static double errorRed;
	private static JButton c;
	private static JButton d;
	public static String lista = "";

	final static int ANCHO_EDICION = 1000;
	final static int ALTO_EDICION = 350;
	final static int ALTO_REJILLA = 8;
	final static int ANCHO_REJILLA = 7;
	final static String FICHERO_PATRONES = "PATRONES.TXT";
	final static String FICHERO_PESOS = "PESOS.TXT";

	public static neuralNetwork nn;

	// configurar GUI y registrar manejador de eventos de ratÛn
	public reconoceObjetos() {

		setVisible(false);

		this.addMouseListener(new java.awt.event.MouseAdapter() {

			@Override
			public void mousePressed(MouseEvent e) {
				this_mousePressed(e);
			}
		});

		this.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {

			@Override
			public void mouseDragged(MouseEvent e) {
				this_mouseDragged(e);
			}
		});

		caja = new JTextField("");
		caja.setBounds(450, 10, 100, 30);
		caja.setEnabled(true);
		caja.setSize(100, 20);
		// caja.setVisible(false);

		labelLetra = new Label();
		labelLetra.setText("Letra :");

		labelOK = new Label();
		labelOK.setText("Ok letra aprendida !!");

		labelOK.setForeground(Color.BLUE);
		labelOK.setSize(200, 10);
		labelOK.setVisible(false);

		labelError = new Label();
		labelError.setText("Error :");

		labelPrintError = new Label();
		labelPrintError.setText(String.valueOf(errorRed));

		labelPrintError.setSize(200, 5);

		b = new JButton("Reconoce");
		b.setSize(new java.awt.Dimension(110, 41));
		b.setVisible(true);
		b.setText("Reconocer");

		c = new JButton("Aprende");
		c.setSize(new java.awt.Dimension(110, 41));
		c.setVisible(true);
		c.setText("Aprende");

		d = new JButton("Limpiar");
		d.setSize(new java.awt.Dimension(110, 41));
		d.setVisible(true);
		d.setText("Limpiar");

		d.setLocation(new java.awt.Point(230, 400));
		c.setLocation(new java.awt.Point(115, 400));
		b.setLocation(new java.awt.Point(1, 400));

		labelPrintError.setLocation(60, 330);
		labelError.setLocation(2, 330);
		caja.setLocation(50, 350);
		labelLetra.setLocation(2, 350);
		labelOK.setLocation(300, 350);
		// b.addActionListener((ActionListener) b);
		
		JSlider happiness = new JSlider(JSlider.HORIZONTAL, 0, 20, 10);
		
		happiness.setMajorTickSpacing(10);
		happiness.setMinorTickSpacing(1);
		happiness.setPaintTicks(true);
		happiness.setBorder(BorderFactory.createEmptyBorder(230,400,10,100));
		happiness.setVisible(true);
		happiness.setLocation(230, 400);
		
		getContentPane().setLayout(null);

		getContentPane().add(caja);
		getContentPane().add(labelLetra);
		getContentPane().add(labelError);
		getContentPane().add(labelOK);
		getContentPane().add(labelPrintError);
		getContentPane().add(happiness);
		
		getContentPane().add(b);
		getContentPane().add(c);
		getContentPane().add(d);

		
		
		// Se le dice al botÛn quÈ tiene que hacer cuando lo pulsemos.
		b.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				try {
					reconoce(utilidades.toBufferedImage(entryImage));
				} catch (FileNotFoundException ex) {
					Logger.getLogger(Pintor.class.getName()).log(Level.SEVERE,
							null, ex);
				} catch (IOException ex) {
					Logger.getLogger(Pintor.class.getName()).log(Level.SEVERE,
							null, ex);
				}

			}
		});

		c.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {

				String imagenBinaria = null;

				if (patronesLetras == null) {
					try {

						imagenBinaria = downSample(utilidades
								.toBufferedImage(entryImage))
								+ utilidades.ascii2bin(caja.getText());

						if (imagenBinaria != null) {
							// utilidades.guardaPatron(FICHERO_PATRONES,
							// imagenBinaria);
						}

					} catch (FileNotFoundException ex) {
						Logger.getLogger(Pintor.class.getName()).log(
								Level.SEVERE, null, ex);
					} catch (IOException ex) {
						Logger.getLogger(Pintor.class.getName()).log(
								Level.SEVERE, null, ex);
					}

				} else {

					String a = caja.getText().toUpperCase();
					
					for (int i = 0; i < a.length(); i++) {

						char s = a.charAt(i);
						char sR = sReconocido.charAt(i);

						if (s != sR) {

							String s1 = Character.toString(s);
							imagenBinaria = patronesLetras[i]+ utilidades.ascii2bin(s1);

							String v = nn.pattern.isPatternValid(imagenBinaria);
							if (v == "") {
								nn.pattern.savePattern("/Volumes/programacion/redneuronal/patrones/", FICHERO_PATRONES, imagenBinaria);
							} else {

								if (v == "2") {

									String l = listaLetras.elementAt(i);
									String[] xy = null;

									xy = l.split(";");

									downSampleRight = Integer.parseInt(xy[2]);
									downSampleLeft = Integer.parseInt(xy[3]);
									downSampleBottom = Integer.parseInt(xy[1]);
									downSampleTop = Integer.parseInt(xy[0]);

									Graphics g = getGraphics();
									g.setColor(Color.WHITE);
									g.clearRect(downSampleLeft, downSampleTop,
											downSampleRight - downSampleLeft,
											downSampleBottom - downSampleTop);
									
									

								}
							}

						}
					}

				}

				labelOK.setVisible(false);
				
				try {
					aprende();
					initNeural();
					caja.setText("");
					// System.exit(0);
				} catch (Exception ex) {
					Logger.getLogger(Pintor.class.getName()).log(Level.SEVERE,
							null, ex);

				}

			}
		});

		d.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {
				clear();
				caja.setText("");

				// System.exit(0);
			}
		});

		setSize(ANCHO_EDICION + 1, 500);

		setLocationRelativeTo(null);

		setResizable(false);
		setVisible(true);
		getContentPane().repaint();

	} // fin del constructor de Pintor

	void redibuja() {

		entryImage = createImage(ANCHO_EDICION, ALTO_EDICION);
		entryGraphics = entryImage.getGraphics();
		entryGraphics.setColor(Color.white);
		entryGraphics.fillRect(0, 0, ANCHO_EDICION, ALTO_EDICION);

		Graphics g = getGraphics();
		g.drawImage(entryImage, 0, 0, this);
		g.setColor(Color.black);
		g.drawRect(0, 0, ANCHO_EDICION, ALTO_EDICION);

		// g.dispose();

	}

	/*
	 * void this_mouseReleased(MouseEvent e) throws FileNotFoundException {
	 * 
	 * 
	 * 
	 * }
	 */
	void this_mousePressed(MouseEvent e) {
		uX = e.getX();
		uY = e.getY();

	}

	void this_mouseDragged(MouseEvent e) {

		entryGraphics.setColor(Color.black);
		entryGraphics.drawOval(e.getX(), e.getY(), 2, 2);

		entryGraphics.drawLine(uX, uY, e.getX(), e.getY());
		// entryGraphics.drawLine(uX-1, uY-1, e.getX(), e.getY());

		Graphics g = getGraphics();

		g.drawImage(entryImage, 0, 0, this);
		uX = e.getX();
		uY = e.getY();
		g.setColor(Color.black);
		g.drawRect(0, 0, ANCHO_EDICION, ALTO_EDICION);

		// utilidades.salvarImagen(utilidades.toBufferedImage(entryImage),"/prueba.png","png");

	}

	public void clear() {

		entryGraphics.setColor(Color.white);
		entryGraphics.fillRect(0, 0, getBounds().width, getBounds().height);
		downSampleBottom = Pintor.downSampleTop = Pintor.downSampleLeft = Pintor.downSampleRight = 0;

		labelOK.setVisible(false);

		ant = -1;
		repaint();
		redibuja();

	}

	protected static boolean hLineClear(int p, int y, int w) {

		for (int i = p; i < w; i++) {
			if (pixelMap[(y * w) + i] != -1) {
				return false;
			}
		}
		return true;
	}

	protected static boolean vLineClear(int x, int w, int h) {
		for (int i = 0; i < h; i++) {
			if (pixelMap[(i * w) + x] != -1) {
				return false;
			}
		}
		return true;
	}

	protected static int findBounds() {

		int w = imageBuffer.getWidth(null);
		int h = imageBuffer.getHeight(null);
		String vc = "";

		// ant = downSampleRight;

		for (int y = downSampleTop; y < h; y++) {
			if (!hLineClear(downSampleRight, y, w)) {
				downSampleTop = y;
				break;
			}
		}

		// left line
		for (int x = downSampleRight; x < w; x++) {
			if (!vLineClear(x, w, h)) {
				downSampleLeft = x;
				break;
			}
		}

		for (int x = downSampleLeft; x < w; x++) {
			if (vLineClear(x, w, h)) {
				downSampleRight = x;
				break;
			}
		}

		for (int y = downSampleTop; y < h; y++) {
			if (hLineClear(downSampleLeft, y, w)) {
				downSampleBottom = y;
				break;
			}
		}

		vc = String.valueOf(downSampleTop) + ";"
				+ String.valueOf(downSampleBottom) + ";"
				+ String.valueOf(downSampleRight) + ";"
				+ String.valueOf(downSampleLeft);

		if (listaLetras.contains(vc)) {

			return -1;
		} else {
			listaLetras.addElement(vc);
			return 1;
			// System.out.println(vc);
		}

	}

	protected boolean hLineClear2(int y, int w, int h) {

		for (int i = downSampleLeft; i < w; i++) {
			if (imageBuffer.getRGB(i, y) != -1) {
				return false;
			}
		}

		return true;

	}

	protected boolean vLineClear2(int x, int w, int h) {

		for (int i = downSampleTop; i < h; i++) {
			if (imageBuffer.getRGB(x, i) != -1) {
				return false;
			}
		}
		return true;
	}

	protected void findBounds_2(int w, int h) {
		// top line

		for (int y = downSampleTop; y < h; y++) {

			// entryGraphics.drawOval(downSampleLeft,y, 2, 2);
			if (!hLineClear2(y, w, h)) {
				downSampleTop = y;
				break;
			}

		}
		// bottom line
		for (int y = h - 1; y >= downSampleTop; y--) {
			if (!hLineClear2(y, w, h)) {
				downSampleBottom = y;
				break;
			}
		}
		// left line
		for (int x = downSampleLeft; x < w; x++) {
			if (!vLineClear2(x, w, h)) {
				downSampleLeft = x;
				break;
			}
		}

		// right line
		for (int x = w - 1; x >= downSampleLeft; x--) {
			if (!vLineClear2(x, w, h)) {
				downSampleRight = x;
				break;
			}
		}

	}

	protected static boolean downSampleQuadrant(int x, int y) {
		int w = imageBuffer.getWidth(null);
		int startX = (int) (downSampleLeft + (x * ratioX));
		int startY = (int) (downSampleTop + (y * ratioY));
		int endX = (int) (startX + ratioX);
		int endY = (int) (startY + ratioY);

		for (int yy = startY; yy <= endY; yy++) {
			for (int xx = startX; xx <= endX; xx++) {
				int loc = xx + (yy * w);

				if (pixelMap[loc] != -1) {
					return true;
				}
			}
		}

		return false;
	}

	public int buscaLetras(BufferedImage imagen) {
		imageBuffer = imagen;

		int w = imageBuffer.getWidth(null);
		int h = imageBuffer.getHeight(null);

		pixelMap = new int[w * h];

		imageBuffer.getRGB(0, 0, w, h, pixelMap, 0, w);

		return (findBounds());

	}

	public String downSample(BufferedImage imagen)
			throws FileNotFoundException, IOException {

		imageBuffer = imagen;

		int w = imageBuffer.getWidth(null);
		int h = imageBuffer.getHeight(null);
		
		
		System.out.println("W=="+w);
		System.out.println("h=="+h);
		
		pixelMap = new int[w * h];

		imageBuffer.getRGB(0, 0, w, h, pixelMap, 0, w);

		//findBounds();

		ratioX = (double) (downSampleRight - downSampleLeft)
				/ (double) ANCHO_REJILLA;
		ratioY = (double) (downSampleBottom - downSampleTop)
				/ (double) ALTO_REJILLA;

		String s = "";
		for (int y = 0; y < ALTO_REJILLA; y++) {
			for (int x = 0; x < ANCHO_REJILLA; x++) {
				if (downSampleQuadrant(x, y)) {

					s = s + "1;";
				} else {

					s = s + "0;";
				}

			}
			// s=s+"\n";
		}

		Graphics g = getGraphics();
		g.setColor(Color.blue);
		g.drawRect(downSampleLeft, downSampleTop, downSampleRight
				- downSampleLeft, downSampleBottom - downSampleTop);

		return (s);

	}
	
public static void speak( String texto) {
		
		String a1=texto;
		String a2="Cepstral Miguel";

		String script="tell current application\n say \""+a1+"\""+" using \""+a2+"\""+"\n"+"end tell"; 

		ScriptEngineManager mgr = new ScriptEngineManager();
		ScriptEngine engine = mgr.getEngineByName("AppleScript");
		ScriptContext context = engine.getContext();
		try {
			engine.eval(script, context);
		} catch (ScriptException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		mgr=null;
		engine=null;
		context=null;
		
	}

	public void reconoce(BufferedImage imagen) throws FileNotFoundException,
			IOException {

		listaLetras = new Vector<String>();
		listaLetras.clear();

		sReconocido = "";
		patronesLetras = null;

		downSampleBottom = Pintor.downSampleTop = Pintor.downSampleLeft = Pintor.downSampleRight = 0;

		String letras = "";
		Graphics g = getGraphics();
		
		BlobDemo blob =  new BlobDemo();
        
		List<Blob> blobList = blob.BlobDemo(imagen);
	
		patronesLetras = new String[blobList.size()];

		for (int v=0; v<blobList.size(); v++) {

				
				downSampleRight = blobList.get(v).xMax-blobList.get(v).xMin;
				downSampleLeft = blobList.get(v).xMin;
				downSampleBottom = blobList.get(v).yMax-blobList.get(v).yMin;
				downSampleTop =  blobList.get(v).yMin;

				imageBuffer = imagen.getSubimage(downSampleLeft,downSampleTop,downSampleRight,downSampleBottom);
				
			/*	String fichero = "/p"+v+".png";
				
				System.out.println(fichero);
				utilidades.salvarImagen(imageBuffer,fichero,"png");*/
				
				dmi = new downloadMosaicImage(imageBuffer, ANCHO_REJILLA, ALTO_REJILLA);
				String s  = dmi.imagenString;
		
				patronesLetras[v] = s;

				
				// Graphics g = getGraphics();
				g.setColor(Color.red);
				g.drawRect(downSampleLeft,downSampleTop,downSampleRight,downSampleBottom );

			}
		
			for (int x=patronesLetras.length-1; x>=0; x--) {
				String p = nn.forwardPropagation(patronesLetras[x]);
				letras = letras + utilidades.bin2ascii(p);
			}
		sReconocido = letras;
		caja.setText(letras);
		
		//speak(letras);

	}

	protected void initImage() {

		entryImage = createImage(ANCHO_EDICION, ALTO_EDICION);
		entryGraphics = entryImage.getGraphics();
		entryGraphics.setColor(Color.white);
		entryGraphics.fillRect(0, 0, ANCHO_EDICION, ALTO_EDICION);

	}

	public void aprende() throws FileNotFoundException, IOException, Exception {

		initNeural();

		while (!nn.isfinishedLearning()) {

			labelPrintError.setText("");
			nn.entrenaRed();

			errorRed = nn.getErrorGlobal();

			labelPrintError.setText(String.valueOf(errorRed));

		}
		// labelOK.setVisible(true);
		
		nn.weight.saveWeights("/Volumes/programacion/redneuronal/pesos/",FICHERO_PESOS);


		//speak("Aprendido");

		reconoce(utilidades.toBufferedImage(entryImage));

	}

	public static void initNeural() throws FileNotFoundException, IOException {
		
		String patron="/Volumes/programacion/redneuronal/patrones/"+FICHERO_PATRONES;
		
		nn = new neuralNetwork(56, 40, 6, patron,1);
		nn.setCoficienteAprendizaje((float) 0.1);
		nn.weight.loadWeight("/Volumes/programacion/redneuronal/pesos/",FICHERO_PESOS);

	}

	@Override
	public void paint(Graphics g) {

		if (entryImage == null) {
			initImage();
		}

	}

	public static void main(String args[]) throws FileNotFoundException,
			IOException {

		reconoceObjetos aplicacion = new reconoceObjetos();

		aplicacion.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		initNeural();

		aplicacion.initImage();
		aplicacion.clear();

	}
} // fin de la clase Pintor
